#if !defined(ximera_physics_ijoint_hpp)
#define ximera_physics_ijoint_hpp

// -----------------------------------------------------------

#include <ximera/enum.hpp>
#include <ximera/common/factory.hpp>
#include <ximera/math/vector3.hpp>
#include <ximera/physics/irigidbody.hpp>

namespace ximera { namespace physics
{
    class IRigidBody;
    
    XIMERA_ENUM(JointType)
        Ball,
        Hinge,
        Slider,
        Universal,
        Hinge2,
        Fixed,
        AMotor
    XIMERA_ENUM_END(JointType)

    class XIMERA_API IJoint
    {
    public:
		virtual ~IJoint();

        virtual JointType type() const = 0;
        virtual void attach(IRigidBody* body0, IRigidBody* body1) = 0;
        virtual void detach() = 0;

        virtual IRigidBody* body0() const = 0;
        virtual IRigidBody* body1() const = 0;
    };

    class XIMERA_API IBallJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Ball;

    public:
        virtual JointType type() const { return jointType; }

        virtual math::Vector3 anchor0() const = 0;
        virtual math::Vector3 anchor1() const = 0;
        virtual void anchor(math::Vector3 const& value) = 0;
    };

    class XIMERA_API IHingeJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Hinge;

    public:
        virtual JointType type() const { return jointType; }

        virtual math::Vector3 anchor0() const = 0;
        virtual math::Vector3 anchor1() const = 0;
        virtual void anchor(math::Vector3 const& value) = 0;

        virtual math::Vector3 axis() const = 0;
        virtual void axis(math::Vector3 const& value) = 0;

        virtual Real angle() const = 0;
    };

    class XIMERA_API ISliderJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Slider;

    public:
        virtual JointType type() const { return jointType; }

        virtual math::Vector3 axis() const = 0;
        virtual void axis(math::Vector3 const& value) = 0;

        virtual math::Vector3 position() const = 0;
    };

    class XIMERA_API IUniversalJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Universal;

    public:
        virtual JointType type() const { return jointType; }

        virtual math::Vector3 anchor0() const = 0;
        virtual math::Vector3 anchor1() const = 0;
        virtual void anchor(math::Vector3 const& value) = 0;

        virtual math::Vector3 axis0() const = 0;
        virtual void axis0(math::Vector3 const& value) = 0;

        virtual math::Vector3 axis1() const = 0;
        virtual void axis1(math::Vector3 const& value) = 0;
    };

    class XIMERA_API IHinge2Joint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Hinge2;

    public:
        virtual JointType type() const { return jointType; }

        virtual math::Vector3 anchor0() const = 0;
        virtual math::Vector3 anchor1() const = 0;
        virtual void anchor(math::Vector3 const& value) = 0;

        virtual math::Vector3 axis0() const = 0;
        virtual void axis0(math::Vector3 const& value) = 0;

        virtual math::Vector3 axis1() const = 0;
        virtual void axis1(math::Vector3 const& value) = 0;
    };

    class XIMERA_API IFixedJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::Fixed;

    public:
        virtual JointType type() const { return jointType; }
    };

    class XIMERA_API IAMotorJoint : public IJoint
    {
    public:
        static JointType::type const jointType = JointType::AMotor;

    public:
        virtual JointType type() const { return jointType; }
    };

    class XIMERA_API JointFactory : public Factory<IJoint, JointType>
    {
    public:
        // TODO: add creation from joint-description
    };
}}

// -----------------------------------------------------------

#endif
